﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media.Media3D;
using System.Windows.Shapes;
using YJYpublicClass;

namespace WindowsFormsApp2.接口类
{
    public  class ProfileProcess
    {
        /// <summary>
        /// 将单条高度数据绘制高度图bmp
        /// </summary>
        /// <param name="profile">输入的单条轮廓</param>
        /// <param name="bmpWidth"></param>
        /// <param name="bmpHeight"></param>
        /// <param name="bitmap"></param>
        public static void Profile2bmp(int[] profile,int cut,int bmpHeight,out Bitmap bitmap)
        {
            // 2. 创建一个位图对象，
            int width = cut;
            int height = bmpHeight;
            bitmap = new Bitmap(width, height, PixelFormat.Format24bppRgb);
            try
            {


                // 假设你的高度数据存储在一个数组中，类似于：

                double[] heightData = new double[profile.Length];

                // 1. 将原始数据转换为物理单位 (0.00001mm)
                for (int i = 0; i < profile.Length; i++)
                {
                    heightData[i] = profile[i] * 0.00001;  // 转换为mm单位
                }
                // 选取中间段部分数据
                int middleStart = (heightData.Length - cut) / 2;
                int middleEnd = middleStart + cut;
                double[] middleHeightData = new double[middleEnd - middleStart];
                Array.Copy(heightData, middleStart, middleHeightData, 0, middleHeightData.Length);



                //获取所有有效点集合
                double valueToExclude = -10000.00000;

                List<double> list = new List<double>();

                foreach (double num in middleHeightData)
                {
                    if (num != valueToExclude)
                    {
                        list.Add(num);
                    }
                }

                double[] newHeightData = list.ToArray();




                // 3. 计算有效数据的最小值和最大值，用于将高度数据映射到图像的像素范围
                double minHeight = double.MaxValue;
                double maxHeight = double.MinValue;

                foreach (var heightValue in newHeightData)
                {
                    if (heightValue < minHeight)
                        minHeight = heightValue;
                    if (heightValue > maxHeight)
                        maxHeight = heightValue;
                }
                //在数据极值的基础上向外扩展10mm使显示明显
                minHeight -= 10;
                maxHeight += 10;
                //将所有无效点替换为最小值
                for (int i = 0; i < middleHeightData.Length; i++)
                {
                    if (middleHeightData[i] == -10000.00)
                    {
                        middleHeightData[i] = minHeight;


                    }
                }


                
                // 4. 绘制走线图（线图）
                using (Graphics g = Graphics.FromImage(bitmap))
                {
                    g.Clear(Color.Black); // 设置背景色为白色
                    Pen pen = new Pen(Color.Yellow, 10); // 使用黑色画笔绘制线条

                    // 5. 绘制走线图（从左到右）
                    for (int i = 1; i < middleHeightData.Length; i++)
                    {

                        // 将高度数据映射到图像的垂直高度范围 [0, height]
                        int y1 = (int)((middleHeightData[i - 1] - minHeight) / (maxHeight - minHeight) * height);
                        int y2 = (int)((middleHeightData[i] - minHeight) / (maxHeight - minHeight) * height);

                        // 绘制从（i-1）到（i）的线段
                        g.DrawLine(pen, i - 1, height - y1, i, height - y2);
                    }
                }
            }
            catch (Exception ex)
            {

                Console.WriteLine(ex.Message);
            }
        }




        /// <summary>
        /// 转换为真实高度mm
        /// </summary>
        /// <param name="rawData"></param>
        /// <returns></returns>
        public static double[] ConvertHeightData(int[] rawData)
        {
            return rawData.Select(x => x * 0.00001).ToArray();
        }


        /// <summary>
        /// 平滑轮廓以减少噪声
        /// </summary>
        /// <param name="data"></param>
        /// <param name="windowSize">平滑核宽度</param>
        /// <returns></returns>
        public static double[] SmoothData(double[] data, int windowSize)
        {
            double[] smoothed = new double[data.Length];
            int halfWindow = windowSize / 2;
            for (int i = 0; i < data.Length; i++)
            {
                int start = Math.Max(0, i - halfWindow);
                int end = Math.Min(data.Length - 1, i + halfWindow);
                double sum = data.Skip(start).Take(end - start + 1).Sum();
                smoothed[i] = sum / (end - start + 1);
            }
            return smoothed;
        }
        #region[通过找平面平台端点测量错边]


        /// <summary>
        /// 通过找平面平台端点测量错边和间隙
        /// </summary>
        /// <param name="intheightData"></param>
        /// <param name="PointsNum">截取宽度</param>
        /// <param name="variWindow">方差核宽度，必须是奇数</param>
        /// <param name="variThreshold">方差筛选阈值，用于判断台阶的结束位置</param>
        /// <param name="minLength">选出的台阶最小长度</param>
        /// <param name="heightDifference">错边量</param>
        /// <param name="gap">间隙</param>
        /// <returns></returns>
        public static int FindNumsByPlatforms(int[] intheightData, int PointsNum,int variWindow,double variThreshold,int minLength,double scaleX, out double heightDifference, out double gap)
        {
            heightDifference = 0;
            gap = 0;

            try
            {

                // 将数据转换为真实距离并存储在 double 数组中
                double[] realDistanceData = ConvertHeightData(intheightData);

                

                // 选取中间段部分数据，假设取中间的一半数据
                int middleStart = (realDistanceData.Length - PointsNum) / 2;
                int middleEnd = middleStart + PointsNum;
                double[] middleHeightData = new double[middleEnd - middleStart];
                Array.Copy(realDistanceData, middleStart, middleHeightData, 0, middleHeightData.Length);

                // 过滤掉单个不连续的无效点
                double[] filteredData = FilterSingleInvalidPoints(middleHeightData);

                // 找出两连续平面中间的无效点段的开始点和结束点
                List<PlatformRegion> Platforms = FindPlatformRegions(filteredData, variWindow, variThreshold, minLength);
                //去除掉无效点平台,反向遍历删除
                for (int i = Platforms.Count - 1; i >= 0; i--) 
                { 
                    double sum = 0;
                    for (int j = Platforms[i].Start;j <= Platforms[i].End;j++)
                    {
                        sum += filteredData[j];

                    }
                    double mean=sum/ Platforms[i].Length;
                    if (mean + 10000 < 5)
                    {
                        Platforms.RemoveAt(i);
                    }
                }


                //判断平台个数，2个为正常，1个认为没有错边和缝隙，2个以上认为筒壁存在异常凸起
                if (Platforms.Count ==2)
                {
                    //根据方差窗口减去固定偏差点数
                    int rightNum = Platforms[0].End ;
                    int leftNum = Platforms[1].Start ;
                    //根据方差窗口
                    double rightHeight = filteredData.Skip(rightNum-variWindow/2).Take(variWindow).Average();
                    double leftHeight = filteredData.Skip(leftNum - variWindow / 2).Take(variWindow).Average();
                    heightDifference = rightHeight - leftHeight;
                    
                    gap=(Math.Abs(leftNum-rightNum) - 2*(int)(variWindow / 2)) *scaleX;

                }
                else if (Platforms.Count == 1)
                {
                    //只有一边，认为间隙大于200mm
                    gap = 200;
                }
                
                    return Platforms.Count;

            }



            catch (Exception ex)
            {
                
                MessageBox.Show(ex.ToString());
                return -1;

            }






        }







        /// <summary>
        /// 定义轮廓中台阶区域
        /// </summary>
        public class PlatformRegion
        {
            public int Start { get; set; }
            public int End { get; set; }
            public double AverageHeight { get; set; }
            public int Length => End - Start + 1;
        }
        /// <summary>
        /// 查找轮廓中的台阶
        /// </summary>
        /// <param name="data">输入轮廓</param>
        /// <param name="varianceWindow">方差核宽度</param>
        /// <param name="varianceThreshold">方差阈值</param>
        /// <param name="minLength">允许平台的最小宽度</param>
        /// <returns></returns>
        public static List<PlatformRegion> FindPlatformRegions(double[] data, int varianceWindow, double varianceThreshold, int minLength)
        {
            var variances = ComputeVariance(data, varianceWindow);
            var regions = new List<PlatformRegion>();
            bool inRegion = false;
            int start = 0;

            for (int i = 0; i < variances.Length; i++)
            {
                if (variances[i] < varianceThreshold)
                {
                    if (!inRegion)
                    {
                        start = i;
                        inRegion = true;
                    }
                }
                else if (inRegion)
                {
                    AddRegion(data, regions, start, i - 1, minLength);
                    inRegion = false;
                }
            }
            if (inRegion) AddRegion(data, regions, start, variances.Length - 1, minLength);
            return regions;
        }

        public static void AddRegion(double[] data, List<PlatformRegion> regions, int start, int end, int minLength)
        {
            if (end - start + 1 >= minLength)
            {
                regions.Add(new PlatformRegion
                {
                    Start = start,
                    End = end,
                    AverageHeight = data.Skip(start).Take(end - start + 1).Average()
                });
            }
        }
        /// <summary>
        /// 求数组方差
        /// </summary>
        /// <param name="data"></param>
        /// <param name="windowSize"></param>
        /// <returns></returns>
        public static double[] ComputeVariance(double[] data, int windowSize)
        {
            double[] variances = new double[data.Length];
            int halfWindow = windowSize / 2;
            for (int i = 0; i < data.Length; i++)
            {
                int start = Math.Max(0, i - halfWindow);
                int end = Math.Min(data.Length - 1, i + halfWindow);
                var segment = data.Skip(start).Take(end - start + 1).ToArray();
                double mean = segment.Average();
                variances[i] = segment.Select(x => (x - mean) * (x - mean)).Average();
                variances[i]=Math.Round(variances[i],7);
            }
            return variances;
        }

        #endregion
        /// <summary>
        /// 图像格式转换：将高度数据转换为灰度深度图像
        /// </summary>
        /// <param name="heightData"></param>
        /// <returns></returns>
        // 
        public static Bitmap ConvertToImage(int[] intheightData,out double scale)
        {
            
            try
            {


                double[] heightData = ConvertHeightData(intheightData);


                //获取所有有效点集合
                double valueToExclude = -10000.00000;

                List<double> list = new List<double>();

                foreach (double num in heightData)
                {
                    if (num != valueToExclude)
                    {
                        list.Add(num);
                    }
                }

                double[] newHeightData = list.ToArray();

                //去除有效点中的偏离值

                newHeightData = RemoveOutliers(newHeightData, 4,out double MeanHeight);

                
                

                double minHeight = double.MaxValue;
                double maxHeight = double.MinValue;

                // 找到最小和最大高度
                foreach (double h in newHeightData)
                {
                    if (h < minHeight) minHeight = h;
                    if (h > maxHeight) maxHeight = h;
                }
                //为了区别背景和较低的台面，有效最小数据-5mm,
                minHeight += -5;

                //将无效值替换为最小高度

                for (int i = 0; i < heightData.Length; i++)
                {
                    if (heightData[i] == -10000.00)
                    {
                        heightData[i] = minHeight;


                    }
                }

                int width = heightData.Length;
                int height = 100; // 图像高度可以根据需要调整
                Bitmap image = new Bitmap(width, height, PixelFormat.Format24bppRgb);

                scale = (maxHeight - minHeight) / 255;
                // 将高度数据映射到灰度值
                for (int x = 0; x < width; x++)
                {
                    byte grayValue = (byte)((heightData[x] - minHeight) / (maxHeight - minHeight) * 255);
                    for (int y = 0; y < height; y++)
                    {
                        image.SetPixel(x, y, Color.FromArgb(grayValue, grayValue, grayValue));

                    }
                }

                return image;
            }
            catch (Exception ex)
            {

                MessageBox.Show(ex.ToString());
                scale = 0;
                return null;
            }
        }
        /// <summary>
        /// 去除偏离较大的点，偏离点将用均值代替
        /// </summary>
        /// <param name="data"></param>
        /// <param name="threshold">阈值，标准差的倍数</param>
        /// <returns></returns>
        public static double[] RemoveOutliers(double[] data, double threshold,out double mean)
        {
             mean = 0;
            //求均值
            foreach (double value in data)
            {
                mean += value;
            }
            mean /= data.Length;
            //求标准差
            double variance = 0;
            foreach (double value in data)
            {
                variance += Math.Pow(value - mean, 2);
            }
            variance /= data.Length;
            double stdDev = Math.Sqrt(variance);
            //得到去除后的数组
            double[] filteredData = new double[data.Length];
            for (int i = 0; i < data.Length; i++)
            {
                if (Math.Abs(data[i] - mean) <= threshold * stdDev)
                {
                    filteredData[i] = data[i];
                }
                else
                {
                    // 可以选择用均值或邻域值替换离群值
                    filteredData[i] = (double)mean;
                }
            }

            return filteredData;
        }

        /// <summary>
        /// 将int数组高度数据保存至CSV,会在指定目录下分日期自动命名保存
        /// </summary>
        /// <param name="intArray"></param>
        /// <param name="filePath"></param>
        /// <exception cref="Exception"></exception>
        public static void SaveIntArrayToCSV(int[] intArray, string filePath)
        {
            try
            {

                string SubFolder = filePath + "\\" + System.DateTime.Now.ToString("yyyyMMdd");
                PublicFuntions.CreateFile(SubFolder);
                string NowTime = System.DateTime.Now.ToString("yyyyMMddHHmmss");
                string SaveName = SubFolder + "\\" + NowTime + ".csv";

                // 使用 StreamWriter 写入文件
                using (StreamWriter writer = new StreamWriter(SaveName))
                {
                    // 遍历数组，将每个元素写入文件
                    for (int i = 0; i < intArray.Length; i++)
                    {
                        // 写入元素
                        writer.WriteLine(intArray[i]);
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception($"保存文件时出错: {ex.Message}");
            }
        }

        /// <summary>
        /// 读取CSV中的高度数据
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        public static int[] ReadHeightDataFromCsv(string filePath)
        {
            List<int> dataList = new List<int>();
            try
            {
                using (StreamReader reader = new StreamReader(filePath))
                {
                    // 跳过表头（如果有）
                    string line;
                    while ((line = reader.ReadLine()) != null)
                    {
                        //跳过无法转换为int32的内容
                        if (int.TryParse(line, out int height))
                        {
                            dataList.Add(height);
                        }
                    } 
                        
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"读取文件时出错: {ex.Message}");
            }
            return dataList.ToArray();
        }

        #region[直接处理断口求值]
        /// <summary>
        /// 找到超景深无效段，通过无效段两端计算错边和间隙
        /// </summary>
        /// <param name="intheightData"></param>
        /// <param name="PointsNum"></param>
        /// <param name="heightDifference"></param>
        /// <param name="gap"></param>
        public static void  GetNumsByInvalidSegment(int[] intheightData,int PointsNum, out double heightDifference,out double gap)
        {
            heightDifference = 0;
            gap = 0;
            
            try
            {
                
                // 将数据转换为真实距离并存储在 double 数组中
                double[] realDistanceData = ConvertHeightData(intheightData);

                //定义所取的点个数
                //PointsNum = 1600;


                // 选取中间段部分数据，假设取中间的一半数据
                int middleStart = (realDistanceData.Length -PointsNum)/ 2;
                int middleEnd = middleStart + PointsNum;
                double[] middleHeightData = new double[middleEnd - middleStart];
                Array.Copy(realDistanceData, middleStart, middleHeightData, 0, middleHeightData.Length);

                // 过滤掉单个不连续的无效点
                double[] filteredData = FilterSingleInvalidPoints(middleHeightData);

                // 找出两连续平面中间的无效点段的开始点和结束点
                List<(int start, int end)> invalidSegments = FindInvalidSegments(filteredData);
                
                
                // 计算每个无效点段对应的两平面高度差和平面间隙
                foreach ((int start, int end) segment in invalidSegments)
                {
                    if (segment.start<5| filteredData.Length-segment.end<5)
                    {
                        Console.WriteLine($"间隙出现在视野边缘，已跳过");
                        Console.WriteLine();
                        continue;
                    }
                     heightDifference = CalculateHeightDifference(filteredData, segment.start, segment.end);
                     gap = CalculateGap(segment.start, segment.end);

                    Console.WriteLine($"无效点段开始点: {segment.start}, 结束点: {segment.end}");
                    Console.WriteLine($"两平面高度差: {heightDifference}");
                    Console.WriteLine($"平面间隙: {gap}");
                    Console.WriteLine();
                }

            }



            catch (Exception ex)
            {

                MessageBox.Show(ex.ToString());

            }
        }
        static double[] FilterSingleInvalidPoints(double[] data)
        {
            double[] filtered = new double[data.Length];
            Array.Copy(data, filtered, data.Length);
            for (int i = 1; i < filtered.Length - 1; i++)
            {
                if (IsInvalidPoint(filtered[i]) && !IsInvalidPoint(filtered[i - 1]) && !IsInvalidPoint(filtered[i + 1]))
                {
                    // 将单个无效点的值设置为前一个有效点的值
                    filtered[i] = filtered[i - 1];
                }
            }
            return filtered;
        }

        static bool IsInvalidPoint(double value)
        {
            // 这里可以根据实际情况定义无效点的判断条件，例如值为某个特殊值表示无效
            return value == -1000000000 * 0.00001;
        }

        static List<(int start, int end)> FindInvalidSegments(double[] data)
        {
            List<(int start, int end)> segments = new List<(int start, int end)>();
            int startIndex = -1;
            for (int i = 0; i < data.Length; i++)
            {
                if (IsInvalidPoint(data[i]))
                {
                    if (startIndex == -1)
                    {
                        startIndex = i;
                    }
                }
                else if (startIndex != -1)
                {
                    segments.Add((startIndex, i - 1));
                    startIndex = -1;
                }
            }
            // 处理最后一段无效点段
            if (startIndex != -1)
            {
                segments.Add((startIndex, data.Length - 1));
            }
            return segments;
        }

        static double CalculateHeightDifference(double[] data, int start, int end)
        {


            // 计算开始点前 5 个点的均值
            double sumBefore = 0;
            int countBefore = 0;
            if (start<2|data.Length-end<2)
            {
                Console.WriteLine("断口出现在视野边缘，无法测量");
                return -1;
            }
            for (int i = Math.Max(0, start - 5); i < start; i++)
            {
                sumBefore += data[i];
                countBefore++;
            }
            double averageBefore = sumBefore / countBefore;

            // 计算结束点后 5 个点的均值
            double sumAfter = 0;
            int countAfter = 0;
            for (int i = end + 1; i < Math.Min(data.Length, end + 6); i++)
            {
                sumAfter += data[i];
                countAfter++;
            }
            double averageAfter = sumAfter / countAfter;

            // 计算高度差
            return averageAfter - averageBefore;
        }

        static double CalculateGap(int start, int end)
        {
            // 固定比例
            const double fixedRatio = 0.18;
            // 计算横向索引数差
            int indexDifference = end - start;
            // 计算平面间隙
            return indexDifference * fixedRatio;
        }



        #endregion



    }
}
